package db

import (
	"errors"
	"fmt"
	"runtime/debug"
	"sync"
	"time"

	"gorm.io/gorm"

	"api/loger"
)

func InsertNewCard(input InputCardInfo) (err error) {
	tx := postdb.Begin()
	defer func() {
		if r := recover(); r != nil {
			tx.Rollback()
			debug.PrintStack()
		}
	}()
	if tx.Error != nil {
		return errors.New("tx.begin failed" + tx.Error.Error())
	}
	cardInfo := CardList{
		CardName:         input.CardName,
		CardIntroduction: input.CardIntroduction,
		IsSupportGroup:   input.IsSupportGroup,
		IsSupportTeam:    input.IsSupportTeam,
		IsSupportVIP:     input.IsSupportVIP,
		IsLimitDays:      input.IsLimitDays,
		IsLimitTimes:     input.IsLimitTimes,
		IsForbidSpecial:  input.IsForbidSpecial,
		IsSupportSpecial: input.IsSupportSpecial,
		AdminAccount:     input.AdminAccount,
		Price:            input.Price,
	}
	if err := tx.Error; err != nil {
		return err
	}
	err = tx.Debug().Model(&CardList{}).Create(&cardInfo).Error
	if err != nil {
		tx.Rollback()
		return err
	}
	loger.Loger.Println("新插入了一个", cardInfo.CardName, cardInfo.CardId, cardInfo.IsForbidSpecial)
	if cardInfo.IsForbidSpecial {
		for _, forbidInfo := range input.ForbidCourseId {
			cardForbidInfo := CardForbidList{
				CourseId: forbidInfo,
				CardId:   cardInfo.CardId,
			}
			err = tx.Debug().Model(&CardForbidList{}).Create(&cardForbidInfo).Error // 使用 Debug 打印插入操作
			if err != nil {
				tx.Rollback()
				return err
			}
		}
	}
	if cardInfo.IsSupportSpecial {
		for _, supportInfo := range input.SupportCourseId {
			cardSupportInfo := CardSupportList{
				CourseId: supportInfo,
				CardId:   cardInfo.CardId,
			}
			err = tx.Debug().Model(&CardSupportList{}).Create(&cardSupportInfo).Error // 使用 Debug 打印插入操作
			if err != nil {
				tx.Rollback()
				return err
			}
		}
	}
	if tx.Error != nil {
		loger.Loger.Println("error:", tx.Error.Error())
		return tx.Error
	}
	err = tx.Commit().Error
	if err != nil {
		loger.Loger.Println(err.Error())
	}
	return err
}
func DeleteNewCardByName(cardName string) (err error) {
	var card CardList
	err = postdb.Where("card_name = ?", cardName).First(&card).Error
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return fmt.Errorf("no card found with name: %s", cardName)
		}
		return err
	}
	// 获取 card_id
	cardId := card.CardId

	// 删除记录
	err = postdb.Where("card_name = ?", cardName).Delete(&CardList{}).Error
	if err != nil {
		return err
	}
	err = postdb.Model(&CardForbidList{}).Where("card_id=?", cardId).Delete(&CardForbidList{}).Error
	if err != nil {
		return err
	}
	err = postdb.Model(&CardSupportList{}).Where("card_id=?", cardId).Delete(&CardSupportList{}).Error
	if err != nil {
		return err
	}
	return nil
}
func SelectAllCardBasicInfo() (cardInfo []CardComplexInfo, err error) {
	// 检索功能是不用事务的
	var cardLists []CardList
	err = postdb.Model(&CardList{}).Find(&cardLists).Error
	if err != nil {
		return nil, err
	}
	cardInfo = make([]CardComplexInfo, len(cardLists))
	for index, card := range cardLists {
		var forbidCourses []CourseBasic = make([]CourseBasic, 0)
		var supportCourse []CourseBasic = make([]CourseBasic, 0)
		// use card id get forbidden course id and want to get course name
		err := postdb.Model(&CardForbidList{}).
			Joins("JOIN courses ON courses.course_id = card_forbid_lists.course_id").
			Where("card_id = ?", card.CardId).
			Select("courses.course_id, courses.course_name").
			Find(&forbidCourses).Error
		if err != nil {
			return nil, err
		}
		cardInfo[index].ForbidCourseInfo = forbidCourses

		err = postdb.Model(&CardSupportList{}).
			Joins("JOIN courses ON courses.course_id = card_support_lists.course_id").
			Where("card_id = ?", card.CardId).
			Select("courses.course_id, courses.course_name").
			Find(&supportCourse).Error

		if err != nil {
			return nil, err
		}
		cardInfo[index].SupportCourseInfo = supportCourse

		cardInfo[index].CardInfo = card
	}
	return cardInfo, nil
}
func InsertNewPurchaseCard(username string, cardId, userId int, money int, endDate time.Time, times int, invitedTeacherId int) (err error) {
	newPurchaseInfo := CardPurchaseRecord{
		AdminUsername:   username,
		CardId:          cardId,
		UserId:          userId,
		Money:           money,
		InviteTeacherId: invitedTeacherId,
		StartDate:       time.Now(),
		EndDate:         endDate,
		Times:           times,
	}
	err = postdb.Model(&CardPurchaseRecord{}).Create(&newPurchaseInfo).Error
	return err
}
func SelectBasicCardInfo(UserCard map[int]BasicCardInfo) (err error) {
	currency := time.Now()
	var purchaseRecords []CardPurchaseRecord
	// find all no expired purchase record
	err = postdb.Model(&CardPurchaseRecord{}).Where("end_date>=?", currency).Find(&purchaseRecords).Error
	if err != nil {
		loger.Loger.Println("money!!!:在检索用户购买会员卡的列表的时候严重问题,error:", err.Error())
		return err
	}
	for _, purchaseRecord := range purchaseRecords {
		var cardInfo CardList
		// select the card information
		err = postdb.Model(&CardList{}).Where("card_id=?", purchaseRecord.CardId).First(&cardInfo).Error
		if err != nil {
			loger.Loger.Println("money!!!:", "在检索用户购买列表的时候检索失败userid:", purchaseRecord.UserId, "error:", err.Error())
			return err
		}
		UserCard[purchaseRecord.UserId] = BasicCardInfo{
			CardId:           cardInfo.CardId,
			PurchaseId:       purchaseRecord.PurchaseId,
			IsSupportGroup:   cardInfo.IsSupportGroup,
			IsSupportTeam:    cardInfo.IsSupportTeam,
			IsSupportVIP:     cardInfo.IsSupportVIP,
			IsLimitDays:      cardInfo.IsLimitDays,
			IsLimitTimes:     cardInfo.IsLimitTimes,
			IsForbidSpecial:  cardInfo.IsForbidSpecial,
			IsSupportSpecial: cardInfo.IsSupportSpecial,
		}
	}
	return nil
}
func SelectPurchaseRecord(userId int) (purchaseRecord []CardPurchaseRecord, err error) {
	err = postdb.Where("user_id=?", userId).Find(&purchaseRecord).Error
	return purchaseRecord, err
}
func DeletePurchaseRecord(purchaseId int) (err error) {
	err = postdb.Where("purchase_id=?", purchaseId).Delete(&CardPurchaseRecord{}).Error
	return err
}
func IsCourseIdInCardSpecialSupport(cardId int, courseId int) (isIn bool, err error) {
	var count int64
	// 查询 CardForbidList 表中是否存在指定的 cardId 和 courseId
	err = postdb.Model(&CardForbidList{}).Where("card_id = ? AND course_id = ?", cardId, courseId).Count(&count).Error
	if err != nil {
		return false, err
	}

	// 如果 count 大于 0，说明记录存在
	return count > 0, nil
}
func IsCourseIdInSpecialForbid(cardId int, courseId int) (isForbid bool, err error) {
	var count int64
	// 查询 CardForbidList 表中是否存在指定的 cardId 和 courseId
	err = postdb.Model(&CardForbidList{}).Where("card_id =? AND course_id =?", cardId, courseId).Count(&count).Error
	if err != nil {
		return false, err
	}

	// 如果 count 大于 0，说明记录存在
	return count > 0, nil
}

// 根据用户id对卡的剩余次数进行更新，如果是会员卡，则purchaseRecord中的times记录-1
func UpdateCardIfTimesCardByUserId(userId, purchaseId int) (err error) {
	var purchaseInfo CardPurchaseRecord
	err = postdb.Model(&CardPurchaseRecord{}).Where("purchase_id=?", purchaseId).First(&purchaseInfo).Error
	if err != nil {
		loger.Loger.Println("cant find the purchase record ")
		return err
	}
	yes, err := isCardLimitTimes(purchaseInfo.CardId)
	if err != nil {
		loger.Loger.Println("cant find this card by cardId", purchaseInfo.CardId)
		return err
	}
	if yes {
		err := UpdateCardTimes(purchaseId, -1)
		if err != nil {
			loger.Loger.Println("error: cant update purchase record times", purchaseId)
			return err
		}
		return nil
	}
	return nil
}
func isCardLimitTimes(cardId int) (yes bool, err error) {
	var cardInfo CardList
	err = postdb.Model(&CardList{}).Where("card_id=?", cardId).First(&cardInfo).Error
	return cardInfo.IsLimitTimes, err
}
func UpdateCardTimes(purchaseId int, change int) (err error) {
	err = postdb.Model(&CardPurchaseRecord{}).Where("purchase_id=?", purchaseId).Update("times", gorm.Expr("times + ?", change)).Error
	return err
}
func InsertNewPurchaseCardByName(username string, cardName, userName string, money int, endDate time.Time, times int, invitedTeacherId int) (err error) {
	// first get the cardid and user id
	var cardId, userId int
	var cardList CardList
	var user User
	err = postdb.Model(&CardList{}).Where("card_name=?", cardName).First(&cardList).Error
	if err != nil {
		loger.Loger.Println("money!!!:", "在检索卡片列表的时候检索失败 cardName:", cardName, "error:", err.Error())
		return err
	}
	err = postdb.Model(&User{}).Where("name=?", userName).First(&user).Error
	if err != nil {
		loger.Loger.Println("money!!!:", "在检索用户列表的时候检索失败 userName:", userName, "error:", err.Error())
		return err
	}
	cardId = cardList.CardId
	userId = user.UserID

	// insert into purchase record

	newPurchaseInfo := CardPurchaseRecord{
		AdminUsername:   username,
		CardId:          cardId,
		UserId:          userId,
		Money:           money,
		InviteTeacherId: invitedTeacherId,
		StartDate:       time.Now(),
		EndDate:         endDate,
		Times:           times,
	}
	err = postdb.Model(&CardPurchaseRecord{}).Create(&newPurchaseInfo).Error
	return err
}
func SelectCardComplexInfoByCardId(cardId int) (cardComplexInfo CardComplexInfo, err error) {
	cardComplexInfo = CardComplexInfo{}
	err = postdb.Model(&CardList{}).Where("card_id=?", cardId).First(&cardComplexInfo.CardInfo).Error
	if err != nil {
		return cardComplexInfo, err
	}
	var cardSupportList []CardSupportList
	var cardForbidList []CardForbidList
	if cardComplexInfo.CardInfo.IsSupportSpecial {
		err = postdb.Model(&CardSupportList{}).Where("card_id=?", cardComplexInfo.CardInfo.CardId).Find(&cardSupportList).Error
		if err != nil {
			return cardComplexInfo, err
		}
		for _, cardSupportInfo := range cardSupportList {
			var course Course
			err = postdb.Model(&Course{}).Where("course_id=?", cardSupportInfo.CourseId).First(&course).Error
			if err != nil {
				return cardComplexInfo, err
			}
			cardComplexInfo.SupportCourseInfo = append(cardComplexInfo.SupportCourseInfo, CourseBasic{
				CourseID:   cardSupportInfo.CourseId,
				CourseName: course.CourseName,
			})
		}
	}
	if cardComplexInfo.CardInfo.IsForbidSpecial {
		err = postdb.Model(&CardForbidList{}).Where("card_id=?", cardComplexInfo.CardInfo.CardId).Find(&cardForbidList).Error
		if err != nil {
			return cardComplexInfo, err
		}
		for _, cardForbidInfo := range cardForbidList {
			var course Course
			err = postdb.Model(&Course{}).Where("course_id=?", cardForbidInfo.CourseId).First(&course).Error
			if err != nil {
				return cardComplexInfo, err
			}
			cardComplexInfo.ForbidCourseInfo = append(cardComplexInfo.ForbidCourseInfo, CourseBasic{
				CourseID:   cardForbidInfo.CourseId,
				CourseName: course.CourseName,
			})
		}
	}
	return cardComplexInfo, nil
}

// 这个课程能被哪些卡预约,考虑到可能出现代码和人工叠加导致的混乱问题,使用优先查看支持表,再最后排除掉一些,来达到查看所有支持的卡的目标
func WhichCardSupportThisCourse(courseId int) ([]CardList, error) {
	//1. 获取到这个课程的信息
	var courseInfo Course
	err := postdb.Model(&Course{}).Where("course_id=?", courseId).First(&courseInfo).Error
	if err != nil && err != gorm.ErrRecordNotFound {
		loger.Loger.Println(err, "error: 检索某个课程详细信息时出现错误courseId:", courseId)
		return nil, err
	}
	var wg sync.WaitGroup
	wg.Add(2)
	var AllCardList []CardList
	var Err error

	go func(*sync.WaitGroup) {
		defer wg.Done()
		// 检索直接能支持的会员卡,并且确定不在特殊禁止内
		var forbidCardId []int
		err = postdb.Model(&CardForbidList{}).Where("course_id=?", courseInfo.CourseId).Pluck("card_id", &forbidCardId).Error
		if err != nil && err != gorm.ErrRecordNotFound {
			loger.Loger.Println(err, "error: 查询课程禁止列表时出现错误courseId:", courseId)
			Err = err
		}
		if len(forbidCardId) != 0 {
			err = postdb.Model(&CardList{}).
				Where("(is_support_team AND ?) OR (is_support_group AND ?) OR (is_support_vip AND ?)", courseInfo.IsTeamType, courseInfo.IsGroupType, courseInfo.IsVipType).
				Where("card_id NOT IN ?", forbidCardId).
				Find(&AllCardList).
				Error
		} else {
			err = postdb.Model(&CardList{}).
				Where("(is_support_team AND ?) OR (is_support_group AND ?) OR (is_support_vip AND ?)", courseInfo.IsTeamType, courseInfo.IsGroupType, courseInfo.IsVipType).
				Find(&AllCardList).
				Error
		}
		if err != nil && err != gorm.ErrRecordNotFound {
			loger.Loger.Println(err, "error: 查询课程能被哪些卡预约时出现错误courseId:", courseId)
			Err = err
		}
	}(&wg)
	// 检索出特殊支持的会员卡
	var SpecialSupportCard []CardList

	go func(*sync.WaitGroup) {
		defer wg.Done()
		var specialSupportCardId []int
		Err = postdb.Model(&CardSupportList{}).Where("course_id=?", courseInfo.CourseId).Pluck("card_id", &specialSupportCardId).Error
		if err != nil && err != gorm.ErrRecordNotFound {
			loger.Loger.Println(err, "error: 查询课程特殊支持列表时出现错误courseId:", courseId)
			Err = err
		}
		err = postdb.Model(&CardList{}).Where("card_id IN ?", specialSupportCardId).Find(&SpecialSupportCard).Error
		if err != nil && err != gorm.ErrRecordNotFound {
			loger.Loger.Println(err, "error: 查询课程能被哪些卡预约时出现错误courseId:", courseId)
			Err = err
		}
	}(&wg)
	if Err != nil {
		return nil, Err
	}
	wg.Wait()
	AllCardList = append(AllCardList, SpecialSupportCard...)
	return AllCardList, nil
}

// 检索会员卡的基本信息和能上哪些课程
func SelectCardInfo(cardId int) (cardInfo CardInfo, err error) {
	cardInfo.CardInfo.CardId = cardId
	err = postdb.Model(&CardList{}).First(&cardInfo.CardInfo).Error
	if err != nil {
		//我在想,这种函数,调用的时候是不是基本不会出现err的情况,出现的概率低到是否粗暴的直接展示是最快最方便的
		return cardInfo, err
	}
	cardInfo.SupportCourseInfo, err = WhichCourseSupportedByThisCard(cardId)
	if err != nil {
		return cardInfo, err
	}
	return cardInfo, nil
}
